﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

namespace AdobePolicyFileServer
{
    class SocketListener :IDisposable
    {
        public const String POLICY_REQUEST = "<policy-file-request/>";
        
		/// <summary>
		/// Variables that are accessed by other classes indirectly.
		/// </summary>
		private Socket clientSocket = null;
		private Thread mainThread=null;
        private bool isForDeletion=false;

        private EventLog logger;

        public EventLog Logger
        {
            get { return logger; }
            set { logger = value; }
        }

        public bool IsForDeletion
        {
            get { return isForDeletion; }
            set { isForDeletion = value; }
        }


		
		/// <summary>
		/// Client Socket Listener Constructor.
		/// </summary>
		/// <param name="clientSocket"></param>
        public SocketListener(Socket clientSocket,EventLog logger)
		{
			this.clientSocket = clientSocket;
            this.logger = logger;
		}


		/// <summary>
		/// Method that starts SocketListener Thread.
		/// </summary>
		public void Start()
		{
			if (clientSocket!= null)
			{
				mainThread = new Thread(new ThreadStart(SocketThreadStart));
				mainThread.Start();
			}
		}

		/// <summary>
		/// Thread method that does the communication to the client. This 
		/// thread tries to receive from client and if client sends any data
		/// then parses it and again wait for the client data to come in a
		/// loop. The recieve is an indefinite time receive.
		/// </summary>
		private void SocketThreadStart()
		{
            if(logger != null)
                logger.WriteEntry("SocketListener Thread replies to " + clientSocket.AddressFamily);
			Byte [] byteBuffer = new Byte[1024];
            try
            {
                StringBuilder strBuilder = new StringBuilder(1024);

                int length = clientSocket.Receive(byteBuffer);
                for (int i = 0; i < length; i++)
                {
                    strBuilder.Append((char)byteBuffer[i]);
                }
                
                String request =  strBuilder.ToString().Trim();
                if (logger != null)
                    logger.WriteEntry("Request:" + request);
                if (request.IndexOf(POLICY_REQUEST) >=0)
                {
                    if (logger != null)
                        logger.WriteEntry("send xml content to client");
                    clientSocket.Send(PolicyContent.Get().XmlContent);
                    Stop();
                }
                else
                    if (logger != null)
                        logger.WriteEntry("not a request for policy");
            }
            catch (SocketException se)
            {
                if (logger != null)
                    logger.WriteEntry(se.Message);
                isForDeletion=true;
            }
		}

		/// <summary>
		/// Method that stops Client SocketListening Thread.
		/// </summary>
		public void Stop()
		{
            if (logger != null)
                logger.WriteEntry("Socket listener stops");
			if (clientSocket!= null)
			{

				clientSocket.Close();

				// Wait for one second for the the thread to stop.
				mainThread.Join(1000);
				
				// If still alive; Get rid of the thread.
				if (mainThread.IsAlive)
				{
					mainThread.Abort();
				}
				mainThread=null;
				clientSocket=null;
				isForDeletion=true;
			}
		}

        #region IDisposable Members

        public void Dispose()
        {
            Stop();
        }

        #endregion
    }
}
